#pragma once
#ifndef _BLOCK_QUEUE_HPP_
#define _BLOCK_QUEUE_HPP_

#include "Lock.hpp"
#include "Cond.hpp"
#include <pthread.h>
#include <queue>

namespace ProConModelModule
{
    using namespace MutexModule;
    using namespace CondModule;

    template <class T>
    class BlockQueue
    {
    private:
        bool IsFull()
        {
            return _cap == _blockqueue.size();
        }

        bool IsEmpty()
        {
            return _blockqueue.empty();
        }
    public:
        BlockQueue(const BlockQueue&) = delete;
        BlockQueue& operator=(const BlockQueue&) = delete;

        BlockQueue(size_t capacity)
            :_cap(capacity)
        {
            _pro_wait_num = 0;
            _con_wait_num = 0;
        }

        void Equeue(T in)
        {
            _mutex.Lock();
            while(IsFull())
            {
                _pro_wait_num += 1;
                _producer.Wait(_mutex);
                _pro_wait_num -= 1;
            }
            _blockqueue.push(in);
            if(_con_wait_num > 0)
            {
                _consumer.Signal();
            }
            _mutex.Unlock();
        }

        void Pop(T* out)
        {
            _mutex.Lock();
            while(IsEmpty())
            {
                _con_wait_num += 1;
                _consumer.Wait(_mutex);
                _con_wait_num -= 1;
            }
            *out = _blockqueue.front();
            _blockqueue.pop();
            if(_pro_wait_num > 0)
            {
                _producer.Signal();
            }
            _mutex.Unlock();
        }

        ~BlockQueue()
        {
            
        }
    private:
        std::queue<T> _blockqueue;
        Mutex _mutex;  // 保护阻塞队列的锁
        Cond _consumer; //消费者的条件变量
        Cond _producer; //生产者环境变量

        //生产者和消费者等待数量
        size_t _pro_wait_num;
        size_t _con_wait_num;
        //阻塞队列容量
        size_t _cap;
    };
}

#endif 